﻿using System;
using Windows.ApplicationModel.Core;

namespace SharpDepend.WinRT
{
    internal class GUITimerManager : IGUITimerManager
    {
        internal class GuiTimer : IGuiTimer
        {
            private TimeSpan mInterval;
            private bool mRunning;
            private bool mQueryStoped;
            private System.Threading.ManualResetEvent mEventReset;

            private static object mLock = new object();

            public static event Action CoreViewAvailable;

            public GuiTimer()
            {
                mEventReset = new System.Threading.ManualResetEvent(true);
            }

            public TimeSpan Interval
            {
                get
                {
                    return mInterval;
                }
                set
                {
                    mInterval = value;
                }
            }

            public event Action Tick;

            public void Start()
            {
                SharpDepend.Manager.ThreadManager.RunThread("GUI timer thread", (Action)Loop);
            }

            public void Stop()
            {
                mRunning = false;
            }

            private async void Loop()
            {
                mQueryStoped = false;
                mRunning = true;

                // Wait until initialized.
                WaitUntilInitializedDone();

                retry:;
                try
                {
                    while (mRunning)
                    {
                        if (Tick != null)
                        {
                            mEventReset.WaitOne();
                            mEventReset.Reset();

                            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                () =>
                                {
                                    Tick();

                                    mEventReset.Set();
                                });
                        }

                        if (mInterval.TotalMilliseconds > 0)
                        {
                            SharpDepend.Manager.ThreadManager.Sleep((int)mInterval.TotalMilliseconds);
                        }
                    }
                }
                catch (Exception)
                {
                    mEventReset.Set();
                    goto retry;
                }

                mQueryStoped = true;
            }

            private static bool mIsDone;
            
            private static void WaitUntilInitializedDone()
            {
                if (mIsDone)
                {
                    return;
                }

                while (true)
                {
                    SharpDepend.Manager.ThreadManager.Sleep(10);

                    try
                    {
                        var mainView = CoreApplication.MainView;

                        if (mainView.CoreWindow == null)
                        {
                            continue;
                        }
                        else
                        {
                            if (mainView.CoreWindow.Dispatcher == null)
                            {
                                continue;
                            }
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }

                    mIsDone = true;
                    break;
                }

                CoreViewAvailable?.Invoke();
            }
        }

        public IGuiTimer CreateTimer()
        {
            return new GuiTimer();
        }
    }
}
